












if __name__ == '__main__':
    import sys
    sys.path.append('../../')


from quant.markets.markets import Markets, RoutingEngine, data_routing_key
from quant.const import DataFrequency
from quant.utils import EventEngine, data_routing_key, logging


class SimMarkets(Markets):
    def __init__(self, real_time_data=False):
        super().__init__()
        self._real_time_data = real_time_data

        self.add_counter = AddCounter()
        self.add_event_engine = AddEventEngine()

        self.clock = EventEngine()
        self.routing_engine = SimRoutingEngine()

        self._last_recv = 0

    def add_market(self, event, exchange, symbol, frequency=DataFrequency.Normal):
        sub_key = subscribe_key(event, exchange, symbol, frequency)
        routing_key = data_routing_key(event, exchange, symbol)
        self.routing_engine.strategy_interest.add(routing_key)

        to_add = self.add_counter.strategy_add(sub_key)
        if to_add:
            self.add_event_engine.put_add_event(event, exchange, symbol, frequency)
            if self._real_time_data:
                super().add_market(event, exchange, symbol, frequency)

    def remove_market(self, event, exchange, symbol, frequency=DataFrequency.Normal):
        return logging.warn('SimMarket cannot remove market')

    def feed_raw(self, event, exchange, symbol, frequency, recv_time, raw):
        assert recv_time >= self._last_recv
        self._last_recv = recv_time

        self.clock.put('clock', recv_time)
        super().feed_raw(event, exchange, symbol, frequency, recv_time, raw)

    def subscribe(self, event, exchange, symbol, handler):
        key = data_routing_key(event, exchange, symbol)
        self.routing_engine.strategy_routing_engine.subscribe(key, handler)

    def subscribe_all(self, handler):
        engine = self.routing_engine.strategy_routing_engine
        key = engine.ALL_DATA
        engine.subscribe(key, handler)

    def matching_add_market(self, event, exchange, symbol, frequency=DataFrequency.Normal):
        sub_key = subscribe_key(event, exchange, symbol, frequency)
        routing_key = data_routing_key(event, exchange, symbol)
        self.routing_engine.matching_interest.add(routing_key)

        to_add = self.add_counter.matching_add(sub_key)
        if to_add:
            self.add_event_engine.put_add_event(event, exchange, symbol, frequency)
            if self._real_time_data:
                super().add_market(event, exchange, symbol, frequency)

    def matching_subscribe(self, event, exchange, symbol, handler):
        key = data_routing_key(event, exchange, symbol)
        self.routing_engine.matching_routing_engine.subscribe(key, handler)

    def matching_subscribe_clock(self, handler):
        self.clock.subscribe('clock', handler)


class AddCounter:
    def __init__(self):
        self._matching_add_count = {}
        self._strategy_add_count = {}

    def strategy_add(self, sub_key):
        count_0 = self._count_added(sub_key)
        count_map = self._strategy_add_count
        count_map[sub_key] = count_map.get(sub_key, 0) + 1
        count_1 = self._count_added(sub_key)

        if count_1 > count_0:
            return True
        else:
            return False

    def matching_add(self, sub_key):
        count_0 = self._count_added(sub_key)
        count_map = self._matching_add_count
        count_map[sub_key] = count_map.get(sub_key, 0) + 1
        count_1 = self._count_added(sub_key)

        if count_1 > count_0:
            return True
        else:
            return False

    def _count_added(self, sub_key):
        match_add = self._matching_add_count.get(sub_key, 0)
        strategy_add = self._strategy_add_count.get(sub_key, 0)
        return max(match_add, strategy_add)


class AddEventEngine:
    def __init__(self):
        self._subscribers = set()
        self._added = []

    def put_add_event(self, event, exchange, symbol, frequency):
        self._added.append((event, exchange, symbol, frequency))
        for fn in self._subscribers:
            fn(event, exchange, symbol, frequency)

    def subscribe_add_event(self, fn):
        for event in self._added:
            fn(*event)
        self._subscribers.add(fn)


class SimRoutingEngine:
    def __init__(self):
        self.matching_interest = set()
        self.matching_routing_engine = RoutingEngine()

        self.strategy_interest = set()
        self.strategy_routing_engine = RoutingEngine()

    def push_data(self, routing_key, market_data):
        if routing_key in self.matching_interest:
            self.matching_routing_engine.push_data(routing_key, market_data)
        if routing_key in self.strategy_interest:
            self.strategy_routing_engine.push_data(routing_key, market_data)


def subscribe_key(event, exchange, symbol, frequency):
    return f'{event}.{exchange}.{symbol}.{frequency}'


if __name__ == '__main__':
    def try_add_counter():
        counter = AddCounter()

        key = 'xxx'

        print(counter.strategy_add(key))
        print(counter.strategy_add(key))
        print(counter.strategy_add(key))

        print(counter.matching_add(key))
        print(counter.matching_add(key))
        print(counter.matching_add(key))
        print(counter.matching_add(key))
        print(counter.matching_add(key))
        print(counter.strategy_add(key))
        print(counter.strategy_add(key))
        print(counter.strategy_add(key))

        key = 'zzz'
        print('-')

        print(counter.strategy_add(key))
        print(counter.strategy_add(key))
        print(counter.strategy_add(key))

        print(counter.matching_add(key))
        print(counter.matching_add(key))
        print(counter.matching_add(key))
        print(counter.matching_add(key))
        print(counter.matching_add(key))
        print(counter.strategy_add(key))
        print(counter.strategy_add(key))
        print(counter.strategy_add(key))

        print(counter._strategy_add_count)
        print(counter._matching_add_count)

    def try_add_ee():
        ee = AddEventEngine()

        def print_add(event, exchange, symbol, frequency):
            print(event, exchange, symbol, frequency)

        ee.put_add_event(1, 2, 3, 4)
        ee.put_add_event(2, 2, 2, 2)
        ee.put_add_event(3, 3, 3, 3)
        ee.subscribe_add_event(print_add)
        ee.put_add_event(4, 4, 4, 4)

    def try_add_ee_real():
        mar = SimMarkets()

        def print_add(event, exchange, symbol, frequency):
            print(event, exchange, symbol, frequency)
        mar.add_event_engine.subscribe_add_event(print_add)

        mar.add_market(1, 1, 1, 1)

        print('---------')
        mar.matching_add_market(1, 1, 1, 1)
        mar.matching_add_market(1, 1, 1, 1)

    def try_sim_swap():
        import sys
        sys.path.append('/root/code')

        from quant.accounts import SimAccounts
        from quant.utils import set_test_mode
        from quant.markets.functions import set_quick_mode
        from strategy.settings import read_setting
        from strategy import read_strategy
        from run import build_market_data
        set_test_mode()

        setting = read_setting('fair_maker2_bnsw')
        setting.log_key = {'log_id': 'sim_bn_btc_usdt'}
        setting.run_service = True

        symbol = 'btc/usdt.swap'
        setting.symbol = symbol
        setting.pricing_param['symbol'] = symbol
        build_market_data(setting, symbol)

        markets = SimMarkets(True)
        accounts = SimAccounts(markets)
        accounts.set_latency(20)
        # accounts.set_balance({'usdt': {'free': 20000, 'frozen': 0}})

        setting.place_spread = [1,    2,    3]
        setting.place_values = [1000, 1000,  1000]
        setting.place_ignore = [5000, 10000, 15000]
        setting.spread_multiplier = 1

        strategy = read_strategy('FairMaker2')
        strategy = strategy(markets, accounts, setting)
        strategy.start()

        strategy.account.info_engine.show_problems()
        # strategy.account.info_engine.show_deal()
        # strategy.account.info_engine.show_user_data()

        markets.matching_add_market('Trade', 'Binance', 'btc/usdt.swap')

        while True:
            input(':')

    def try_sim_history():
        import sys
        import time
        sys.path.append('/root/code')

        from quant.accounts import SimAccounts
        from quant.utils import set_test_mode, FileRawLogger, RawReplayer
        from quant.markets.functions import set_quick_mode
        from strategy.settings import read_setting
        from strategy import read_strategy
        from run import build_market_data

        set_test_mode()

        setting = read_setting('fair_maker2_bnsw')
        setting.log_key = {'log_id': 'sim_bn_gala_swap_22'}
        setting.run_service = True

        symbol = 'gala/usdt.swap'
        setting.symbol = symbol
        setting.pricing_param['symbol'] = symbol
        build_market_data(setting, symbol)

        markets = SimMarkets(False)
        accounts = SimAccounts(markets)
        accounts.set_latency(20)
        # accounts.set_balance({'usdt': {'free': 20000, 'frozen': 0}})

        setting.place_spread = [1,    2,    3]
        setting.place_values = [1000, 1000,  1000]
        setting.place_ignore = [5000, 10000, 15000]

        strategy = read_strategy('FairMaker2')
        strategy = strategy(markets, accounts, setting)
        strategy.start()

        strategy.account.info_engine.show_problems()
        strategy.account.info_engine.show_deal()
        # strategy.account.info_engine.show_user_data()

        markets.matching_add_market('Trade', 'Binance', 'gala/usdt.swap')

        logger = FileRawLogger('gala-2bt-12.01', '/root/raw')
        replayer = RawReplayer(markets, logger)

        while True:
            replayer.push_interval(1)
            time.sleep(0.1)

    def try_sim_spot():
        import sys
        import time
        sys.path.append('/root/code')

        from quant.accounts import SimAccounts
        from quant.utils import set_test_mode, FileRawLogger, RawReplayer
        from quant.markets.functions import set_quick_mode
        from strategy.settings import read_setting
        from strategy import read_strategy
        from run import build_market_data

        set_test_mode()

        setting = read_setting('fair_maker2_bn')

        setting.log_key = {'log_id': 'sim_bn_gala_spot_a2'}
        setting.run_service = True

        symbol = 'gala/usdt'
        setting.symbol = symbol
        setting.pricing_param['symbol'] = symbol
        build_market_data(setting, symbol)

        markets = SimMarkets(False)
        accounts = SimAccounts(markets)
        accounts.set_latency(20)
        accounts.set_balance({'usdt': {'free': 20000, 'frozen': 0}})

        setting.place_spread = [1,    2,    3]
        setting.place_values = [1000, 1000,  1000]
        setting.place_ignore = [5000, 10000, 15000]

        strategy = read_strategy('FairMaker2')
        strategy = strategy(markets, accounts, setting)
        strategy.start()

        strategy.account.info_engine.show_problems()
        strategy.account.info_engine.show_deal()
        # strategy.account.info_engine.show_user_data()

        markets.matching_add_market('Trade', 'Binance', 'gala/usdt')

        logger = FileRawLogger('gala-2bt-12.01', '/root/raw')
        replayer = RawReplayer(markets, logger)

        while True:
            replayer.push_interval(1)
            time.sleep(0.1)

    def try_sim_spot_busd():
        import sys
        import time
        sys.path.append('/root/code')

        from quant.accounts import SimAccounts
        from quant.utils import set_test_mode, FileRawLogger, RawReplayer
        from quant.markets.functions import set_quick_mode
        from strategy.settings import read_setting
        from strategy import read_strategy
        from run import build_market_data

        set_test_mode()

        setting = read_setting('fair_maker2_bnb')

        setting.log_key = {'log_id': 'sim_bn_busd'}
        setting.run_service = True

        symbol = 'btc/busd'
        setting.symbol = symbol
        setting.pricing_param['symbol'] = symbol
        build_market_data(setting, symbol)

        markets = SimMarkets(True)
        accounts = SimAccounts(markets)
        accounts.set_latency(20)
        accounts.set_balance({'busd': {'free': 20000, 'frozen': 0}})

        setting.spread_multiplier = 1
        setting.amount_multiplier = 10
        setting.ignore_multiplier = 10
        setting.pricing_param['quote_value'] = 100_0000

        strategy = read_strategy('FairMaker2')
        strategy = strategy(markets, accounts, setting)
        strategy.start()

        strategy.account.info_engine.show_problems()
        strategy.account.info_engine.show_deal()
        # strategy.account.info_engine.show_user_data()

        markets.matching_add_market('Trade', 'Binance', 'btc/busd')

        while True:
            input(':')

    try_sim_spot_busd()




















































